package com.dbflow5.query;

import com.dbflow5.sql.Query;

import java.util.Arrays;

/**
 * Description: Simple interface for objects that can be used as [Operator]. This class
 * takes no type parameters for primitive objects.
 */
public interface IConditional extends Query {

    Operator<?> isNull();

    Operator<?> isNotNull();

    Operator<?> is(IConditional conditional);

    Operator<?> is(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> eq(IConditional conditional);

    Operator<?> eq(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> concatenate(IConditional conditional);

    Operator<?> isNot(IConditional conditional);

    Operator<?> isNot(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> notEq(IConditional conditional);

    Operator<?> notEq(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> like(IConditional conditional);

    Operator<?> like(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> notLike(IConditional conditional);

    Operator<?> notLike(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> glob(IConditional conditional);

    Operator<?> glob(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> like(String value);

    Operator<?> match(String value);

    Operator<?> notLike(String value);

    Operator<?> glob(String value);

    Operator<?> greaterThan(IConditional conditional);

    Operator<?> greaterThan(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> greaterThanOrEq(IConditional conditional);

    Operator<?> greaterThanOrEq(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> lessThan(IConditional conditional);

    Operator<?> lessThan(BaseModelQueriable<?> baseModelQueriable);

    Operator<?> lessThanOrEq(IConditional conditional);

    Operator<?> lessThanOrEq(BaseModelQueriable<?> baseModelQueriable);

    Operator.Between<?> between(IConditional conditional);

    Operator.Between<?> between(BaseModelQueriable<?> baseModelQueriable);

    Operator.In<?> in(IConditional firstConditional, IConditional... conditionals);

    Operator.In<?> in(BaseModelQueriable<?> firstBaseModelQueriable,
                      BaseModelQueriable<?>... baseModelQueriables);

    Operator.In<?> notIn(IConditional firstConditional, IConditional... conditionals);

    Operator.In<?> notIn(BaseModelQueriable<?> firstBaseModelQueriable,
                         BaseModelQueriable<?>... baseModelQueriables);

    Operator<?> plus(BaseModelQueriable<?> value);

    Operator<?> minus(BaseModelQueriable<?> value);

    Operator<?> div(BaseModelQueriable<?> value);

    Operator<?> times(BaseModelQueriable<?> value);

    Operator<?> rem(BaseModelQueriable<?> value);

    default Operator.In<?> in(IConditional[] values) {
        if(values.length == 1){
            return in(values[0]);
        }else {
            return this.in(values[0], Arrays.copyOfRange(values, 1, values.length));
        }
    }

    default Operator.In<?> notIn(IConditional[] values) {
        if(values.length == 1){
            return notIn(values[0]);
        }else {
            return this.notIn(values[0], Arrays.copyOfRange(values, 1, values.length));
        }
    }

    default <T> Operator.In<?> in(BaseModelQueriable<T>[] values) {
        if(values.length == 1){
            return in(values[0]);
        }else {
            return this.in(values[0], Arrays.copyOfRange(values, 1, values.length));
        }
    }

    default <T> Operator.In<?> notIn(BaseModelQueriable<T>[] values) {
        if(values.length == 1){
            return notIn(values[0]);
        }else {
            return this.notIn(values[0], Arrays.copyOfRange(values, 1, values.length));
        }
    }
}

